#Requires AutoHotkey v2.0

; 脚本核心对象
clip := {

    ; 是否启用热键(0 不启用, 1 启用)
    hotkeyEnabled: 1,

    ; 配置文件路径			   
    configFile: A_ScriptDir "\batData.properties",

    ; 数据文件路径 
    dataFile: A_ScriptDir "\data.txt", 

    ; 粘贴文本            
    texts: [], 
    
    ; 可变粘贴文本索引
    textsVarIndex: [],

    ; 数据文件为空时粘贴的默认文本                                    
    defText: "#无数据#",

    ; 初始索引为 1（AutoHotkey 数组从 1 开始）			   
    index: 1, 

    ; 是否保留索引（1 保留，0 不保留）                                   
    keepIndex: 0,

    ; 上次检测的文件大小			   
    dataFileSize: 0,  

    ; 数据文件是否改变（0 未改变，1 已改变）
    dataFileChanged: 0,

    ; 数据模型(LIST 序列,AUTO-INCREMENT 自增)                             
    dataModel: "LIST",

    ; 数据模型不可改变(0 可以改变, 1 不可改变)
    dataModelFinal: 0
    
}

; 自定义热键 Ctrl + C
; ^c:: CustomCtrlV("^c")

; 自定义热键 Ctrl + V
^v:: CustomCtrlV("^v")

; 自定义热键 Ctrl + Alt + Q
^!q:: CustomCtrlAltQ("^!q")

; ----- 函数(回调) -----

; 按下 Ctrl + C 执行的事件
CustomCtrlC(hotKeyName){
    ; 待完善
}

; 按下 Ctrl + V 执行的事件 
CustomCtrlV(hotKeyName){

    global clip ; 声明全局变量
    switch clip.dataModel{
        
        case "AUTO": C_auto_increment()       
        case "AUTO-INCREMENT": C_auto_increment()    
        default : C_list()
    }
    
    
}
; 按下 Ctrl + Alt + Q 执行的事件 切换热键是否启用
CustomCtrlAltQ(hotKeyName){
    
    ; 切换是否启用热键
    if(clip.hotkeyEnabled = 1){
        clip.hotkeyEnabled := 0
        Hotkey("^v",CustomCtrlV, "OFF")
    }else{
        clip.hotkeyEnabled :=1
        Hotkey("^v",CustomCtrlV, "ON")
    }
}

; ----- 函数(固定) -----

; 读取文件内容的函数
C_readFile(filePath) {

    global clip ; 声明全局变量
    fileContent := FileRead(filePath)  ; 使用函数风格读取文件内容
    lines := StrSplit(fileContent, "`n") ; 按行分割文件内容
    
    ; texts 初始化为空数组
    clip.texts :=[]
    
    ; 分析数据模型
    C_isDataModel(fileContent)

    ; LIST模式的处理方式
    if(clip.dataModel = "LIST"){

        ; 去除每行的换行符并检查空行
        for index, line in lines {
    	    trimmedLine := Trim(line, "`r`n")
            if (trimmedLine != "") {
                clip.texts.Push(trimmedLine)
            }
        }
        clip.dataFileSize := GetFileSize(clip.dataFile)
        return
    }

    ; AUTO-INCREMENT模式的处理方式
    if(clip.dataModel = "AUTO-INCREMENT"){
        C_auto_incrementHandle(fileContent)
    }
}

; 分析数据模型
C_isDataModel(fileContent){

    global clip ; 声明全局变量
    ; MsgBox fileContent
    if(clip.dataModelFinal = 0){
        if (InStr(fileContent, "[$AUTO-INCREMENT$]")) {
            clip.dataModel := "AUTO-INCREMENT"
            MsgBox "2024年5月28日00:50:08"
        } else if(InStr(fileContent, "[$AUTO$]")){
            clip.dataModel := "AUTO-INCREMENT"
        } else { 
            ; 默认数据模型为LIST
            clip.dataModel := "LIST"
        }
        
    }
}

; 处理LIST模型
C_list(){

    global clip ; 声明全局变量

    ; 检查 数据文件是否发生改变，如果发生改变，将texts数组设为空
    if(clip.dataFileChanged = 1 ){ ; 如果确定数据文件已经发生变化(就没必要再次检测了)
        clip.dataFileChanged := CheckFileChange(clip.dataFile, clip.dataFileSize)
    }

    if(clip.dataFileChanged = 1){
    	clip.texts := [] ; 将texts数组设为空(重新获取)

	    if(clip.keepIndex = 0){ ; 索引重置(如果需要)
	        clip.index := 1
	    }
    }

    ; 检查 texts 数组是否为空,为空则从数据文件中读取数据
    if (clip.texts.Length = 0){

	    ; 读取文件内容并将其存储在 texts 数组中
        C_readFile(clip.dataFile)

	    ; 没有读到数据
	    if (clip.texts.Length = 0){
	        clip.texts.Push(clip.defText)
	        ; MsgBox clip.defText
	    }
    }
    
    ; 发送当前索引对应的文本(格式化后)
    Send(EscapeSpecialChars(clip.texts[clip.index]))

    ; 将索引递增
    clip.index++
        
    ; 如果索引超出数组长度，重新设置为 1
    if (clip.index > clip.texts.Length) {
        clip.index := 1
    }
    
}

; 处理AUTO-INCREMENT模型
C_auto_increment(){
    
    global clip ; 声明全局变量

    ; 检查 数据文件是否发生改变，如果发生改变，将texts数组设为空
    if(clip.dataFileChanged = 1 ){ ; 如果确定数据文件已经发生变化(就没必要再次检测了)
        clip.dataFileChanged := CheckFileChange(clip.dataFile, clip.dataFileSize)
    }

    if(clip.dataFileChanged = 1){
    	clip.texts := [] ; 将texts数组设为空(重新获取)

	    if(clip.keepIndex = 0){ ; 索引重置(如果需要)
	        clip.index := 1
	    }
    }

    ; 检查 texts 数组是否为空,为空则从数据文件中读取数据
    if (clip.texts.Length = 0){

	    ; 读取文件内容并将其存储在 texts 数组中
        C_readFile(clip.dataFile)

	    ; 没有读到数据
	    if (clip.texts.Length = 0){
	        clip.texts.Push(clip.defText)
	        ; MsgBox clip.defText
	    }
    }
}

; 处理AUTO-INCREMENT模型(具体实现)
C_auto_incrementHandle(Str){

    global clip ; 声明全局变量
    static variable := false ; 判断字符是属于变量字符还是常规字符
    static StrN := "" ; 常规字符串
    static StrV := "" ; 变量字符串
    
    ; 删除无效字符
    Str := StrReplace(Str, "{$AUTO$}", "")
    Str := StrReplace(Str, "{$AUTO-INCREMENT$}", "")

    loop parse, Str{
        
        if(A_LoopField = "{"){
            variable := true
            Clip.texts.Push(StrN)
            StrN := ""
        }
    
        if(variable){
            StrV .= A_LoopField
        }else{
            StrN .= A_LoopField
        }
        
        if(A_LoopField = "}"){
            variable := false
            Clip.texts.Push(Trim(StrV,"{}"))
            StrV := ""
            Clip.textsVarIndex.Push(Clip.texts.Length)
        }
        
    }
    
    ; loop 里面仅仅做测试
    loop {
        loop{
            if(index = clip.textsVarIndex[j]){
                MsgBox(index "<-变量->" Clip.texts[index])
                break
            } else {
                MsgBox(index "<-常规->" Clip.texts[index])
                break
            }
            j++
            if(j > clip.textsVarIndex.Length){
                break
            }
        }
        index++
        if(index > Clip.texts.Length){
            break
        }
    }
}

; ----- 函数(复用) -----

; 用于转义特殊字符的函数
EscapeSpecialChars(str) {
    ; 定义需要转义的特殊字符及其替换值
    specialChars := ["#", "!", "^", "+","[", "]"]
    replacements := ["{#}", "{!}", "{^}", "{+}", "{[}", "{]}"]

    ; 循环遍历特殊字符数组，进行替换
    Loop specialChars.Length {
        str := StrReplace(str, specialChars[A_Index], replacements[A_Index])
    }
    Return str
}

; 检查文件大小变化的函数(fileToCheck 文件，上次检查时文件的大小)
CheckFileChange(fileToCheck, lastSize) {
    ; 获取当前文件大小
    fileSize := FileGetSize(fileToCheck)

    ; 检查文件大小是否变化
    if (fileSize != lastSize) {
        lastSize := fileSize
	; 文件大小未发生变化返回1
        return 1
    }

    ; 文件大小未发生变化返回0
    return 0
}


; 获取文件大小的辅助函数
GetFileSize(fileToCheck) {
    file := FileOpen(fileToCheck, "r")
    if !file
        return -1  ; 返回 -1 表示文件打开失败

    fileSize := file.Length
    file.Close()
    return fileSize
}



